package com.newfiber.common.redis.service;

import com.newfiber.common.core.web.support.IRedisPrefix;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

/**
 * spring redis 工具类
 * 
 * @author newfiber
 **/
@Component
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public class RedisService{

    @Resource
    public RedisTemplate redisTemplate;

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param redisPrefix 缓存的键值
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final IRedisPrefix redisPrefix, final String key, final T value){
        redisTemplate.opsForValue().set(redisPrefix.wrapperRedisKey(key), value);
    }

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final IRedisPrefix redisPrefix, final String key, final T value, final Long timeout, final TimeUnit timeUnit){
        redisTemplate.opsForValue().set(redisPrefix.wrapperRedisKey(key), value, timeout, timeUnit);
    }

	/**
	 * 缓存基本的对象，Integer、String、实体类等
	 *
	 * @param key 缓存的键值
	 * @param value 缓存的值
	 * @param timeout 时间
	 */
	public <T> void setCacheObject(final IRedisPrefix redisPrefix, final String key, final T value, final Long timeout){
		redisTemplate.opsForValue().set(redisPrefix.wrapperRedisKey(key), value, timeout, TimeUnit.SECONDS);
	}

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功；false=设置失败
     */
    public boolean expire(final IRedisPrefix redisPrefix, final String key, final long timeout){
        return expire(redisPrefix, key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功；false=设置失败
     */
    public boolean expire(final IRedisPrefix redisPrefix, final String key, final long timeout, final TimeUnit unit){
        return redisTemplate.expire(redisPrefix.wrapperRedisKey(key), timeout, unit);
    }

    /**
     * 获取有效时间
     *
     * @param key Redis键
     * @return 有效时间
     */
    public long getExpire(final IRedisPrefix redisPrefix, final String key){
        return redisTemplate.getExpire(redisPrefix.wrapperRedisKey(key));
    }

    /**
     * 判断 key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public Boolean hasKey(final IRedisPrefix redisPrefix, String key){
        return redisTemplate.hasKey(redisPrefix.wrapperRedisKey(key));
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final IRedisPrefix redisPrefix, final String key){
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(redisPrefix.wrapperRedisKey(key));
    }

	/**
	 * 获得缓存的基本对象。
	 *
	 * @param key 缓存键值
	 * @return 缓存键值对应的数据
	 */
	public <T> T getCacheObject(final String key){
		ValueOperations<String, T> operation = redisTemplate.opsForValue();
		return operation.get(key);
	}

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final IRedisPrefix redisPrefix, final String key){
        return redisTemplate.delete(redisPrefix.wrapperRedisKey(key));
    }

	/**
	 * 删除对象
	 *
	 * @param key
	 */
	public boolean deletePatternObject(final IRedisPrefix redisPrefix, final String key){
		Collection<String> keys = keys(redisPrefix, key);
		return deleteObject(keys);
	}

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public boolean deleteObject(final Collection collection){
        return redisTemplate.delete(collection) > 0;
    }

    /**
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final IRedisPrefix redisPrefix, final String key, final List<T> dataList){
        Long count = redisTemplate.opsForList().rightPushAll(redisPrefix.wrapperRedisKey(key), dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final IRedisPrefix redisPrefix, final String key){
        return redisTemplate.opsForList().range(redisPrefix.wrapperRedisKey(key), 0, -1);
    }

    /**
     * 缓存Set
     *
     * @param key 缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final IRedisPrefix redisPrefix, final String key, final Set<T> dataSet){
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(redisPrefix.wrapperRedisKey(key));
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext()){
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final IRedisPrefix redisPrefix, final String key){
        return redisTemplate.opsForSet().members(redisPrefix.wrapperRedisKey(key));
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final IRedisPrefix redisPrefix, final String key, final Map<String, T> dataMap){
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(redisPrefix.wrapperRedisKey(key), dataMap);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final IRedisPrefix redisPrefix, final String key){
        return redisTemplate.opsForHash().entries(redisPrefix.wrapperRedisKey(key));
    }

    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final IRedisPrefix redisPrefix, final String key, final String hKey, final T value){
        redisTemplate.opsForHash().put(redisPrefix.wrapperRedisKey(key), hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final IRedisPrefix redisPrefix, final String key, final String hKey){
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(redisPrefix.wrapperRedisKey(key), hKey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final IRedisPrefix redisPrefix, final String key, final Collection<Object> hKeys){
        return redisTemplate.opsForHash().multiGet(redisPrefix.wrapperRedisKey(key), hKeys);
    }

    /**
     * 删除Hash中的某条数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return 是否成功
     */
    public boolean deleteCacheMapValue(final IRedisPrefix redisPrefix, final String key, final String hKey){
        return redisTemplate.opsForHash().delete(redisPrefix.wrapperRedisKey(key), hKey) > 0;
    }

	/**
	 * 返回所有(一个或多个)给定 key* 的值。
	 * 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nil 。因此，该命令永不失败。
	 */
	public List<String> mGet(final IRedisPrefix pattern, String key) {
		Collection<String> keys = keys(pattern, key);
		return redisTemplate.opsForValue().multiGet(keys);
	}

	/**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final IRedisPrefix pattern){
        return redisTemplate.keys(pattern.getModuleKey() + "*");
    }

	/**
	 * 获得缓存的基本对象列表
	 *
	 * @param pattern 字符串前缀
	 * @return 对象列表
	 */
	public Collection<String> keys(final IRedisPrefix pattern, String key){
		return redisTemplate.keys(pattern.wrapperRedisKey(key) + "*");
	}


    /**
     * 自增 1
     *
     * @param redisPrefix 字符串前缀
     * @param key keyName
     * @return 数值
     */
    public Long  increment(final IRedisPrefix redisPrefix, final String key){
        ValueOperations<String,String> operation = redisTemplate.opsForValue();
        return operation.increment(redisPrefix.wrapperRedisKey(key));
    }


    /**
     * 自减 1
     *
     * @param redisPrefix 字符串前缀
     * @param key keyName
     * @return 数值
     */
    public Long decrement(final IRedisPrefix redisPrefix, final String key){
        ValueOperations<String,String> operation = redisTemplate.opsForValue();
        return operation.decrement(redisPrefix.wrapperRedisKey(key));
    }
}
